﻿using com.iot.core.exception;
using com.iot.core.ext;
using com.iot.core.infrastructure;
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;

namespace com.iot.core.data
{
    //add-migration
    //update-database
    //Remove-Migration
    public class IotDbContext : DbContext
    {

        public IotDbContext(DbContextOptions<IotDbContext> options)
   : base(options)
        {
        }
        //protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
        //{
        //    base.ConfigureConventions(configurationBuilder);
        //    configurationBuilder.DefaultTypeMapping<IdNameDto>();
        //}


        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            Console.WriteLine("OnModelCreating...." + this.ContextId.ToString());

            var entityMethod = typeof(ModelBuilder).GetMethod("Entity", new Type[] { });


            var typeFinder = Singleton<ITypeFinder>.Instance;
            var entityTypes = typeFinder
              .FindClassesOfType<BaseEntity>()
              .Select(a => a)
              .ToList();

            foreach (var type in entityTypes)
            {
                entityMethod.MakeGenericMethod(type).Invoke(modelBuilder, new object[] { });
            }


            foreach (var entity in modelBuilder.Model.GetEntityTypes())
            { 
                // Replace column names            
                foreach (var property in entity.GetProperties())
                {
                    property.SetColumnName(property.GetColumnName().ToSnakeCase());
                }
            }


            var _NopDBStartup = typeFinder
             .FindClassesOfType<INopDBStartup>()
             .Select(startup => (INopDBStartup)Activator.CreateInstance(startup))
              .OrderBy(startup => startup.Order)
             .ToList();
            foreach (var dbstart in _NopDBStartup)
            {
                dbstart.OnModelCreating(modelBuilder);
            }


            base.OnModelCreating(modelBuilder);
        }


        public override int SaveChanges()
        {
            BeforeSave();
            try
            {
                return base.SaveChanges();
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            return 0;
        }
        public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
        {
            BeforeSave();
            return await base.SaveChangesAsync();
        }

        void BeforeSave()
        {
            var m = this.ChangeTracker;

            foreach (var entry in m.Entries())
            {
                if (entry.State == EntityState.Added
                    || entry.State == EntityState.Modified)
                {
                    var validationContext = new ValidationContext(entry.Entity);
                    Validator.ValidateObject(entry.Entity, validationContext);


                    var validationResults = new List<ValidationResult>();

                    var succcess = Validator.TryValidateObject(entry.Entity, validationContext, validationResults, true);
                    if (!succcess)
                    {
                        var msg = string.Join("\n", validationResults.Select(r => r.ErrorMessage)); ;
                        throw new MyException(10, msg); ;
                    }

                }

            }
        }
    }

}
